home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-10-04 | 39.1 KB | 1,167 lines |
- package sub_arctic.lib;
- import sub_arctic.input.*;
- import sub_arctic.anim.timer;
- import sub_arctic.anim.timer_transition;
- import sub_arctic.anim.transition;
- import sub_arctic.anim.animation_agent;
-
- import java.awt.Event;
- import java.util.Vector;
-
- /**
- * This class implements a style-nuetral listbox. This is the input
- * behavior which is matched with the output behavior of listbox_display. <P>
- *
- *
- * All callbacks pass the currently focused on object as their data
- * to the callback. Summary of the callback behavior of this object: <P>
- * <DL>
- * <DT> SINGLE_CLICK_PENDING
- * <DD> This callback is sent when the mouse is first released from an
- * object. This is the "early" callback which precedes either a
- * SINGLE_CLICK_FINAL or DOUBLE_CLICK.
- * <DT> SINGLE_CLICK_FINAL
- * <DD> This is the callback that is sent when the listbox is sure that
- * no double click will be forthcoming. This may be sent in response to
- * a timeout, or may be sent immediately following the SINGLE_CLICK_PENDING
- * in cases where a double click is not allowed.
- * <DT> DOUBLE_CLICK
- * <DD> This is sent when a double click is detected on a particular object.
- * It will always be preceeded by a SINGLE_CLICK_PENDING callback.
- * <DT> DRAG
- * <DD> This message is sent when the user depresses the mouse on the
- * focused object and then moves the mouse some number of pixels (default
- * of 4 pixels). This message is only sent when you have previously
- * called set_allow_dragging(true).
- * </DL>
- *
- * @author Ian Smith
- * @version $Id: listbox.java,v 1.12 1996/10/04 23:03:27 iansmith Exp $
- */
- public class listbox extends listbox_display implements simple_draggable, pressable, timer {
- /**
- * This use of this constant means that listboxes in this group
- * will have their content synchronized.
- */
- public static final int SYNCH_CONTENT=1<<0;
- /**
- * This use of this constant means that listboxes in this group
- * will have their selections synchronized.
- */
- public static final int SYNCH_SELECTION=1<<1;
- /**
- * This use of this constant means that listboxes in this group
- * will have their focused objects synchronized.
- */
- public static final int SYNCH_FOCUSED=1<<2;
- /**
- * This use of this constant means that listboxes in this group
- * will have their displayed x coordinates synchronized.
- */
- public static final int SYNCH_X_COORD=1<<3;
- /**
- * This use of this constant means that listboxes in this group
- * will have their displayed y coordinates synchronized.
- */
- public static final int SYNCH_Y_COORD=1<<4;
- /**
- * This mask holds what the current set of synchronization constants
- * are. This defaults to synchronizing the y coordinates, the selected
- * set and the focused object; this set of synchronizations is good
- * for viewing database records.
- */
- protected int _synch_mask = SYNCH_SELECTION | SYNCH_FOCUSED | SYNCH_Y_COORD;
-
- /**
- * This variable holds whether or not we are allowed to have multiple
- * selections.
- */
- protected boolean _single_selection=false;
- /**
- * This constant holds the callback number for double click.
- * When you get a double click callback the parameter passed to the
- * callback function is the element which was double clicked on. It is
- * returned via the convert_to_object() part of the list_element
- * interface.
- */
- public static final int DOUBLE_CLICK=0;
- /**
- * This constant holds the callback number for a drag.
- * When you get a drag callback the parameter passed to the callback
- * function is the element which was dragged. It is
- * returned via the convert_to_object() part of the list_element
- * interface.
- */
- public static final int DRAG=1;
- /**
- * This constant holds the callback number for a tentative
- * first click action. When this callback is received, it
- * may be the case that a double click will follow this
- * callback. If no double click actually occurs, then a
- * SINGLE_CLICK_FINAL call will be forthcoming.<P>
- *
- * The object passed to the callback function is the
- * currently focused on item.
- */
- public static final int SINGLE_CLICK_PENDING=2;
- /**
- * This constant holds the callback number for a a single
- * click. When this call is made, there is no chance that
- * a double click will result from this first click, thus
- * actions which need to be sure that no double click can
- * occur should handle this callback rather than
- * SINGLE_CLICK_PENDING.<P>
- *
- * The object passed as the parameter to the callback function
- * when this callback is run is the currently focused on
- * object. The event field of the callback may be an
- * animation event
- * when this callback is run because this callback can be
- * run not response to a user event, but rather a timeout.
- */
- public static final int SINGLE_CLICK_FINAL=3;
- /**
- * Return whether or not we are only allowing single selections.
- *
- * @return boolean true if this listbox will only allow single selections
- */
- public boolean single_selection() { return _single_selection;}
- /**
- * This function changes the selection mode for this object. Calling
- * this function will result in set of selections being cleared.
- * @param boolean s true if you want to allow only single selections
- */
- public void set_single_selection(boolean s) {
- clear_selected();
- _single_selection=s;
- }
- /**
- * This storage is used by the interactor to know if a double click
- * might be coming. If this variable is null, there is no transition
- * scheduled, and thus we are not waiting on a possible double click.
- */
- protected transition _double_click_trans;
- /**
- * This is how many milliseconds to wait for a double click.
- */
- protected int _double_click_delay=350;
- /**
- * This is what the user originally clicked on, thus where we
- * want to check to see if they are if we get a fast second click.
- */
- protected int _double_click_loc;
- /**
- * This variable determines who the next listbox is in the circularly
- * linked list of listboxes we are synchronizing together. If you
- * don't use groups, this will always point to this object.
- */
- protected listbox next = this;
- /**
- * This value is the value of the currently focused on object.
- * This object may or may not be in the selected set.
- */
- protected int _focused=-1;
- /**
- * This variable is used to store the x position that began a drag.
- * If the DRAG callback is going to be called, the listbox needs to
- * know when the user has dragged DRAG_DISTANCE from the origin of
- * the drag.<P>
- *
- * This variable (and its y counterpart) wouldn't need to be here
- * if we were using a different drag protocol, as it would give us
- * the starting x and y coordinate. However, I felt that
- * it would add needless complexities to the code use a different
- * protocol since that protocol would only be utilized in one place,
- * but would be visible all over the code.
- */
- private static int drag_x_origin;
- /**
- * This variable is used to store the y position that began a drag.
- * If the DRAG callback is going to be called, the listbox needs to
- * know when the user has dragged DRAG_DISTANCE from the origin of
- * the drag.
- */
- private static int drag_y_origin;
- /**
- * This boolean is true if a drag has started which might require
- * a DRAG callback.
- */
- private static boolean drag_in_progress=false;
- /**
- * This boolean is true if the drag message has already been sent
- * the user level code.
- */
- private static boolean drag_message_sent=false;
- /**
- * This is the variable that holds the index of the object we clicked
- * on when we possibly are beginning a drag. Since the feedback to
- * the user might need to be different, we can't guarantee that
- * this is the focused object when the drag starts. Thus, we have
- * to keep this variable to store the focused on object.
- */
- private static int drag_focus_index;
- /**
- * This is the distance that the user must drag the focused object
- * in either X or Y before the system will send a drag message.
- */
- protected int DRAG_DISTANCE=4;
- /**
- * This is the callback object for this listbox.
- */
- protected callback_object _callback_obj=null;
- /**
- * Retreive the callback object for this listbox.
- * @return callback_object the object handling callbacks from this listbox
- */
- public callback_object callback_obj() { return _callback_obj;}
- /**
- * Set the callback object for this listbox.
- * @param callback_object co the new callback object
- */
- public void set_callback_obj(callback_object co) {
- _callback_obj=co;
- }
- /**
- * This boolean should be set to true if you want your object
- * to be able to drag objects out of its list. This defaults to
- * false.
- */
- protected boolean _allow_dragging=false;
- /**
- * Retreive the current state of draggability. If this is true,
- * then objects may be dragged out of this list.
- * @return boolean true if objects may be dragged
- */
- public boolean allow_dragging() { return _allow_dragging;}
- /**
- * Set the current state of dragging. If you set this to true,
- * you should be prepared to receive DRAG callbacks and further
- * you should act on them when they are received. In particular,
- * you should remove this listbox from the focus set of the
- * simple_drag_object. <P>
- *
- * Although we are allowing you to not really handle a drag from
- * the list (based on some condition of your choosing), users
- * may become confused when they attempt to change their selection
- * in the listbox and nothing happens. This is because the state
- * machine for doing selection is not "turned on" when the listbox
- * is expecting you to respond to a DRAG callback.
- * @param boolean a the new state of dragging
- */
- public void set_allow_dragging(boolean a) {_allow_dragging=a;}
- /**
- * This variable is used to allow the system to know where the
- * last valid object was before the user's mouse went "out of
- * bounds."
- */
- protected int _last_valid;
-
-
- /**
- * Return the currently focused on object. This object may or
- * may not be in the set of selected objects. This object will
- * be returned to you via the "convert_to_object" method of
- * the list element. You will get a value of null if no object
- * currently is focused.
- * @return int the index of the currently focused object
- */
- public Object focused() {
- list_element el;
- Object obj;
- /* safety check */
- if (_focused==-1) return null;
- /* retrieve the element */
- el=(list_element)_child_display.child(_focused);
- /* get the object */
- obj=el.convert_to_object();
- /* if its not null, return it */
- if (obj!=null) return obj;
- /* otherwise return the object itself */
- return el;
- }
- /**
- * Return the currently focused on object as a list_element.
- * This object may or may not be in the set of selected objects.
- * You will get a value of null if no object currently is focused.
- *
- * @return int the index of the currently focused object
- */
- public list_element focused_raw() {
- list_element el;
-
- /* safety check */
- if (_focused==-1) return null;
- /* retrieve the element */
- el=(list_element)_child_display.child(_focused);
- /* send it home */
- return el;
- }
-
- /**
- * This function sets the focused on object to a given object
- * index. If you give a bad index value, no object ends up being
- * the focus.
- *
- * @param int indx the index of the object that you wish to become the focus
- */
- public void set_focused(int indx) {
- list_element old,new_focus;
-
- if ((synch_mask() & SYNCH_FOCUSED) !=0) {
- /* we need to do it */
- if (synch_in_progress) {
- /* end of the road for this puppy */
- return;
- }
- /* need to remember where we have been */
- synch_in_progress=true;
- /* tell the next guy */
- next.set_focused(indx);
- /* we are done synchronizing */
- synch_in_progress=false;
- }
- /* is there one? */
- if (_focused!=-1) {
- old=(list_element)_child_display.child(_focused);
- /* did it somehow get changed */
- if (old.focused()) {
- old.lost_focus();
- }
- }
- /* is there a new focus? */
- if (indx!=-1) {
- /* there is a new focus in town */
- new_focus=(list_element)_child_display.child(indx);
- /* make it the focus and remember that */
- new_focus.become_focus();
- }
- /* keep track */
- _focused=indx;
- return;
- }
- /**
- * This object is the current "starting point" for a drag interactor.
- * This start point is the one around which all drags occur; it is
- * the balancing point for a drag. It is only valid during a drag
- * and only when the selection mode allows multiple selections.
- */
- protected int _start;
- /**
- * This is the index of the object we were over the last time we
- * got any input during a drag sequence. This value may be -1 if we
- * weren't over any object before (we were out of bounds).
- */
- protected int _prev;
- /**
- * This function can derive an index position of a list_element
- * from an event in this object's coordinate system.
- * @param event evt the event we are interested in
- * @return int the index number of the element or -1 if not on any element
- */
- public int index_for_event(event evt) {
- event e=new event(evt);
- /* transform the coordinate systems down */
- e.global_to_local(_child_display);
- if ((e.local_x() <0) || (e.local_y()<0) ||
- (e.local_x()>=_child_display.w()) ||
- (e.local_y()>=_child_display.h())) {
- return -1;
- }
- /* convert to an index value */
- return _child_display.index_for_pixel(e.local_y());
- }
- /**
- * Construct a listbox of a given size. We default to always
- * having a vertical scrollbar and never having a horizontal one.
- *
- *
- * @param int w the width of the listbox in pixels
- * @param int h the height of the listbox in pixels
- * @param boolean s true if you want to allow only single selections
- * @param callback_object co the callback object for this listbox
- */
- public listbox(int w, int h, boolean s,callback_object co)
- {
- super(w,h);
- _single_selection=s;
- _callback_obj=co;
- /* set the status */
- set_vertical_status(listbox_display.SCROLLBAR_ALWAYS);
- set_horizontal_status(listbox_display.SCROLLBAR_NEVER);
-
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /**
- * Start a drag. This just sends the start drag message to one of
- * the appropriate handlers for the selection mode this box is in.
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_start(event evt, Object user_info) {
- if (_single_selection) {
- return(drag_start_one(evt,user_info));
- } else {
- return(drag_start_multiple(evt,user_info));
- }
- }
- /**
- * Continue a drag. This just sends the drag_feedback message to one of
- * the appropriate handlers for the selection mode this box is in.
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_feedback(event evt, Object user_info) {
- if (_single_selection) {
- return(drag_feedback_one(evt,user_info));
- } else {
- return(drag_feedback_multiple(evt,user_info));
- }
- }
- /**
- * End a drag. This just sends the drag_end message to one of
- * the appropriate handlers for the selection mode this box is in.
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_end(event evt, Object user_info) {
- if (_single_selection) {
- return(drag_end_one(evt,user_info));
- } else {
- return(drag_end_multiple(evt,user_info));
- }
- }
- /**
- * Start a drag for a listbox which is in single selection mode.
- *
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_start_one(event evt, Object user_info) {
- int loc=index_for_event(evt);
-
- /* is there a drag going on? */
- if (drag_in_progress) {
- /* there is a drag going on, bail out */
- return true;
- }
- /* normal case: clear the selection and add this object to
- * the selected set */
- clear_selected();
- add_to_selected_set(loc,loc);
- return true;
- }
- /**
- * Continue a drag for a listbox which is in single selection mode.
- *
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_feedback_one(event evt, Object user_info) {
- int loc=index_for_event(evt);
-
- /* are they doing a drag? */
- if (drag_in_progress) {
- /* have they dragged enough ?*/
- if (drag_ready(evt.local_x(), evt.local_y())) {
- /* if the user has already gotten a drag message, the
- drag hook code won't send it again */
- drag_hook(evt,user_info);
- }
- /* if there is a drag, we are done */
- return true;
- }
- /* make sure that if they are out of bounds, we don't do anything */
- if (loc!=-1){
- /* normally, we just clear the current selection and reset to
- the object under the cursor */
- clear_selected();
- /* select the right objects */
- add_to_selected_set(loc,loc);
- /* update the last valid location */
- _last_valid=loc;
- }
- return true;
- }
- /**
- * End a drag for a listbox which is in single selection mode.
- *
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_end_one(event evt, Object user_info) {
- int loc=index_for_event(evt);
-
- /* is the user doing a drag? */
- if (drag_in_progress) {
- /* no matter what happens here, we need to reset the state */
- drag_in_progress=false;
- /* there are two cases in which the drag message
- sent might be false... */
- if (drag_message_sent==false) {
- /* first one is that the distance travelled is too small... */
- if (drag_ready(evt.local_x(), evt.local_y())==true) {
- /* its not too small, so the user is telling us to get
- out of the way, so we will ... i.e. this call is in
- response to the user removing us from the selected set*/
- return true;
- }
- /* this case is the one where the user just clicked on the
- focused item... we can just run the code for the normal
- case and recover */
- } else {
- /* we have sent the drag message and the user-level code didn't
- handle it for some reason... we are just going to ignore this
- input, really this probably an error */
- return true;
- }
- }
- /* if they are out of bounds, just substitute the last valid
- place they were */
- if (loc==-1) {
- loc=_last_valid;
- }
- /* normal case: clear the selection make this object the
- only thing in the selected set */
- clear_selected();
- add_to_selected_set(loc,loc);
- /* start a timer */
- _double_click_trans=new timer_transition(this,_double_click_delay);
- manager.animation.schedule_transition(_double_click_trans);
- /* remember where he clicked */
- _double_click_loc=loc;
- /* set the focus */
- set_focused(loc);
- /* run the callback */
- single_click_pending_hook(evt);
- return true;
- }
- /**
- * Start a drag for a listbox which is in multiple selection mode.
- *
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_start_multiple(event evt, Object user_info) {
- int loc=index_for_event(evt);
-
- /* is it shifted? */
- if ((evt.modifiers() & Event.SHIFT_MASK) !=0 ) {
- /* do they have a current object?... if not give them one*/
- if (_focused==-1) {
- set_focused(loc);
- }
- /* make the focused object be the start */
- _start=_focused;
- } else {
- /* do they have the control down? */
- if ((evt.modifiers() & Event.CTRL_MASK) !=0) {
- _start=loc;
- } else {
- /* if there is a drag in progress, we don't do anything on
- start */
- if (!drag_in_progress) {
- clear_selected();
- _start=loc;
- } else {
- /* it is progress, bail out of here */
- return true;
- }
- }
- }
- /* we now have start set up the way we want ... just the right range*/
- add_to_selected_set(_start,loc);
- /* we want to know where we have been */
- _prev=loc;
- /* done */
- return true;
- }
- /**
- * Continue a drag for a listbox which is in multiple selection mode.
- *
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_feedback_multiple(event evt, Object user_info) {
- int loc=index_for_event(evt);
- int large_x, small_x, large_y, small_y;
-
- /*if there is a drag in progress, there is only one thing to
- do... see if they dragged far enough ..*/
- if (drag_in_progress) { /* are they in a drag? */
- /* have they dragged enough ?*/
- if (drag_ready(evt.local_x(), evt.local_y())) {
- /* if the user has already gotten a drag message, the
- drag hook code won't send it again */
- drag_hook(evt,user_info);
- }
- /* if there is a drag, we are done */
- return true;
- }
- /* if they go out of bounds, we don't do anything */
- if (loc==-1) {
- return true;
- }
- /* in bounds... are they in the same object? */
- if (loc==_prev) {
- /* they are, bail out */
- return true;
- }
- /* new object might not be visible */
- ensure_visible(loc);
-
- /* they are somewhere else... were they in bounds before? */
- if (_prev!=-1) {
- /* they were in bounds before ... remove it from the selected set*/
- remove_from_selected_set(_prev,loc);
- }
- /* set the new objects into the set */
- add_to_selected_set(_start,loc);
- /* make sure we remember where we were */
- _prev=loc;
- /* done */
- return true;
- }
- /**
- * End a drag for a listbox which is in multiple selection mode.
- *
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean drag_end_multiple(event evt, Object user_info) {
- int loc=index_for_event(evt);
-
- /* is the user doing a drag? */
- if (drag_in_progress) {
- /* no matter what happens here, we need to reset the state */
- drag_in_progress=false;
- /* there are two cases in which the drag message
- sent might be false... */
- if (drag_message_sent==false) {
- /* first one is that the distance travelled is too small... */
- if (drag_ready(evt.local_x(), evt.local_y())==true) {
- /* its not too small, so the user is telling us to get
- out of the way, so we will ... i.e. this call is in
- response to the user removing us from the selected set*/
- return true;
- }
- /* if we get here, the user has simply clicked on focused
- item... we need to get back into a state in which
- the normal code can run ... so we replicate the code that
- should have run at start time */
- clear_selected();
- _start=drag_focus_index; /* don't use loc: it might be -1! */
- _prev=drag_focus_index;
- /* add this object to the selected set */
- add_to_selected_set(_start,_start);
- } else {
- /* we have sent the drag message and the user-level code didn't
- handle it for some reason... we are just going to ignore this
- input, really this probably an error */
- return true;
- }
- }
- /* do the normal feedback */
- drag_feedback_multiple(evt,user_info);
- /* now just set the focus to be where they left off */
- set_focused(_prev);
- /* run the callback for the release */
- single_click_pending_hook(evt);
- /* did the user drag out a region?*/
- if (loc==_start) {
- /* he didn't drag out a region, start a timer going */
- _double_click_trans=new timer_transition(this,_double_click_delay);
- manager.animation.schedule_transition(_double_click_trans);
- /* remember where he clicked */
- _double_click_loc=loc;
- } else {
- /* we know there is not going to be a double click so go ahead
- * and send the message about the first click ending */
- single_click_final_hook(evt);
- }
- return true;
- }
- /**
- * Handle the mouse button being depressed on our area.
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean press(event evt, Object user_info) {
- int loc=index_for_event(evt);
- interactor drag_obj;
-
- /* is it in bounds? */
- if (loc==-1) {
- return false;
- }
- /* update the last valid location */
- _last_valid=loc;
-
- /* check for possible double click */
- if (_double_click_trans!=null) {
- /* we know we got another click in time */
- manager.animation.remove_transition(_double_click_trans);
- /* is it in the same place? */
- if (loc==_double_click_loc) {
- /* it is in the same place, run the callback */
- double_click_hook(evt,user_info);
- /* remove the transition */
- _double_click_trans=null;
- /* we are done here */
- return true;
- }
- }
- /* is the user trying to pick up the focused object */
- if (_focused==loc) {
- /* ok, the user started out on the object that is focused,
- a drag may be needed ... make sure the cntrl and shift
- are not depressed */
- if (allow_dragging() &&
- ((evt.modifiers() & Event.SHIFT_MASK) ==0) &&
- ((evt.modifiers() & Event.CTRL_MASK)==0)) {
- /* we are in a drag and have not yet sent the drag message */
- drag_in_progress=true;
- drag_message_sent=false;
- /* store the location of the start of the drag */
- drag_x_origin=evt.local_x();
- drag_y_origin=evt.local_y();
- /* store the index of the focus, since the default start
- behavior is to clear the focus */
- drag_focus_index=_focused;
- }
- }
- manager.simple_drag_focus.set_focus_to(this,evt,null);
- return true;
- }
- /**
- * Handle the mouse button being released on our area. This never
- * happens, as we use a focus based agent which short circuits
- * the input.
- * @param event evt the event in question
- * @param Object user_info (not used)
- */
- public boolean release(event evt, Object user_info) {
- return false;
- }
- /**
- * We don't allow ourselves to ever be picked directly. The
- * listbox_helper object will put us in the pick list <I>only</I>
- * in the case where the main display area was picked on.
- *
- * @param int pt_x the x coordinate of the point
- * @param int pt_y the y coordinate of the point
- * @param pick_collector the object to put yourself in if you are picked
- */
- public void pick(int pt_x, int pt_y, pick_collector pick_list)
- {
- /* just go into the children */
- pick_within_children(pt_x, pt_y, pick_list);
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /**
- * Generate a little different string for the listbox.
- * @return String a simple dump of this object
- */
- public String toString() {
- StringBuffer result = new StringBuffer();
-
- /* Do a minimal dump */
- result.append("listbox:[x="); result.append(x());
- result.append(", y="); result.append(y());
- result.append(", w="); result.append(w());
- result.append(", h="); result.append(h());
- result.append("]");
-
- return result.toString();
- }
- /**
- * Add this listbox to a group of listboxes which have (possibly)
- * synchronized input and output.
- * @param listbox a listbox in the group you wish this listbox to be added to
- */
- public void add_to_group(listbox l) {
- listbox points_to_l;
-
- /* we want points_to_l to be a listbox which points to l */
- if (l.next==l) {
- points_to_l=l;
- }
- else {
- points_to_l=l.find_sibling_of(l);
- }
- /* link us in to that circularly linked list */
- next=l;
- points_to_l.next=this;
- }
- /**
- * This is a utility function which finds the object in a linked list
- * which points to some target listbox.
- * @param listbox target the listbox whose sibling you want to find
- * @return listbox the listbox that points to the target
- */
- protected listbox find_sibling_of(listbox target) {
-
- /* try this one... */
- if (next==target) {
- return this;
- }
- /* go to the next one */
- /* assumed invariant: Circularly linked lists will always find target */
- return (next.find_sibling_of(target));
- }
- /**
- * This function will cause a listbox to be removed from the group
- * it is currently in and return to its own group (of one).
- */
- public void remove_from_group() {
-
- /* if you aren't in a group, this does nothing */
- if (next==this) return;
- /* otherwise: find who points at us */
- listbox sib=find_sibling_of(this);
- /* tell them to adjust their pointers */
- sib.next=next;
- /* we are now in our own group */
- next=this;
- }
- /**
- * Retreive the current mask of synchronization values.
- * @return int a bitmask representing the state of the synchronization for this listbox
- */
- public int synch_mask() { return _synch_mask;}
- /**
- * Set the synchronization mask to a new value. You should OR together
- * the set of flags that you want to be in the mask from the set of
- * SYNCH_X_COORD, SYNCH_Y_COORD, SYNCH_FOCUSED, SYNCH_SELECTION, and
- * SYNCH_CONTENT.
- * @param int mask the new synchronization mask
- */
- public void set_synch_mask(int mask) {
- _synch_mask=mask;
- }
- /**
- * This boolean is true when we are in the process of performing a
- * synchronization activity. This prevents us from getting confused
- * because of the circularly linked list.
- */
- protected boolean synch_in_progress=false;
- /**
- * We override the set selected method so we can synchronize listboxes.
- * Be that synchronized selected objects are synchronized in number
- * not in content. If you want synchronized content you have to
- * use SYNCH_CONTENT.
- *
- * @param Vector selected the objects which are now to be selected
- */
- public void set_selected(Vector selected) {
- Vector indexes=new Vector();
- int index,i;
- interactor obj;
-
- if ((synch_mask() & SYNCH_SELECTION) !=0) {
- /* we need to do it */
- if (synch_in_progress) {
- /* end of the road for this puppy */
- return;
- }
- /* need to remember where we have been */
- synch_in_progress=true;
- /* if selected is empty, we need to not do anything */
- if (selected!=null) {
- /* transform the data into something with indexes*/
- for (i=0; i<selected.size();++i) {
- /* grab the individual element */
- obj=(interactor)selected.elementAt(i);
- /* see if its in the child list */
- index=_child_display.find_child(obj);
- /* if its not -1, we add it */
- if (index!=-1) {
- indexes.addElement(new Integer(index));
- } else {
- System.out.println("HM. Index probably shouldn't be -1");
- }
- }
- }
- /* forward this message on to others */
- next.set_selected_by_index(indexes);
- /* we are done synchronizing */
- synch_in_progress=false;
- }
- /* we never want a double click to happen if we have changed
- * what is selected.
- */
- _double_click_trans=null;
- /* we need to clear the focused on item */
- set_focused(-1);
- /* just do the superclass behavior */
- super.set_selected(selected);
- }
- /**
- * We override this method to make sure that we keep the listbox
- * selection state synchronized.
- * @param Vector selected a vector of Integer objects
- */
- public void set_selected_by_index(Vector selected) {
-
- if ((synch_mask() & SYNCH_SELECTION) !=0) {
- /* we need to do it */
- if (synch_in_progress) {
- /* end of the road for this puppy */
- return;
- }
- /* need to remember where we have been */
- synch_in_progress=true;
- /* tell the next guy */
- next.set_selected_by_index(selected);
- /* we are done synchronizing */
- synch_in_progress=false;
- }
- /* we need to clear the focused on item */
- set_focused(-1);
- /* do the superclass behavior */
- super.set_selected_by_index(selected);
- }
- /**
- * We override this function to allow synchronization of the
- * listboxes.
- * @param int y the coordinate to display
- */
- public void set_scrolled_y(int y) {
- if ((synch_mask() & SYNCH_Y_COORD) !=0) {
- /* we need to do it */
- if (synch_in_progress) {
- /* end of the road for this puppy */
- return;
- }
- /* need to remember where we have been */
- synch_in_progress=true;
- /* tell the next guy */
- next.set_scrolled_y(y);
- /* we are done synchronizing */
- synch_in_progress=false;
- }
- /* just do superclass behavior */
- super.set_scrolled_y(y);
- }
- /**
- * We override this function to allow synchronization of the
- * listboxes.
- * @param int x the x coordinate to display
- */
- public void set_scrolled_x(int x) {
- if ((synch_mask() & SYNCH_X_COORD) !=0) {
- /* we need to do it */
- if (synch_in_progress) {
- /* end of the road for this puppy */
- return;
- }
- /* need to remember where we have been */
- synch_in_progress=true;
- /* tell the next guy */
- next.set_scrolled_x(x);
- /* we are done synchronizing */
- synch_in_progress=false;
- }
- /* just do superclass behavior */
- super.set_scrolled_x(x);
- }
- /**
- * This method gets called when the double click timer expires. This
- * method clears the state variable so we know that subsequent clicks
- * are not part of a double click. It also fires the callback to
- * inform the userlevel code what happened.
- * @param event e the animation event which caused time to expire
- */
- public void time_expired(event evt) {
- _double_click_trans=null;
- /* run the callback */
- single_click_final_hook(evt);
- }
- /**
- * This function is called by the listbox if it detects a second
- * click in a short period of time on the object just released
- * on. <P>
- *
- * The user should be aware that the default behavior of this
- * code is to run a callback (DOUBLE_CLICK). If you override
- * this method, you will not get the call to the callback
- * unless you call super. Further, most users shouldn't
- * need to override this as the can put their response in
- * the callback object. <P>
- *
- * When you get a double click the parameter passed to the callback
- * function is the element which was double clicked on. It is
- * returned via the convert_to_object() part of the list_element
- * interface.
- *
- * @param event evt the event in question
- * @param Object user_info (not currently used)
- */
- protected void double_click_hook(event evt, Object user_info) {
- Vector v;
- /* is there a callback object?*/
- if (callback_obj()!=null) {
- /* grab the selected set */
- v=contents();
- callback_obj().callback(this,evt,DOUBLE_CLICK,
- v.elementAt(_double_click_loc));
- }
- }
- /**
- * This function is called by the listbox code when it detects that
- * the currently focused item has been pressed on. <P>
- *
- * The user should be aware that the default behavior of this
- * code is to run a callback (DRAG). If you override
- * this method, you will not get the call to the callback
- * unless you call super. Further, most users shouldn't
- * need to override this as the can put their response in
- * the callback object.<P>
- *
- * When you get a drag callback the parameter passed to the callback
- * function is the element which was dragged. It is
- * returned via the convert_to_object() part of the list_element
- * interface.
- *
- * @param event evt the event in question
- * @param Object user_info (not currently used)
- */
- protected void drag_hook(event evt, Object user_info) {
- Vector v;
-
- /* if we have already sent this message, then we want to abort */
- if (drag_message_sent) return;
- /* is there a callback object?*/
- if (callback_obj()!=null) {
- /* grab the selected set */
- v=contents();
- callback_obj().callback(this,evt,DRAG,
- v.elementAt(drag_focus_index));
- }
- /* we have sent the message ... note: we should not set the state
- * of the drag_message sent until AFTER we have really called the
- * callback as it may examine this value during the callback itself */
- drag_message_sent=true;
- }
- /**
- * If the user is in the middle of a double click and the contents
- * change we don't want the double click to happen.
- *
- * @param Vector contents the new contents of this object (all the objects in this vector must be list_elements)
- */
- public void set_contents(Vector contents) {
- _double_click_trans=null;
- /* we need to clear the focused on item */
- set_focused(-1);
- super.set_contents(contents);
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /**
- * This function is called when the listbox is sure that no further
- * click is forthcoming and that the callback code for the
- * SINGLE_CLICK_FINAL can be safely called.<P>
- *
- * Most users shouldn't need to override this method, as they can
- * put their code to handle the single click in the callback object.<P>
- *
- * The object passed as the parameter to the callback function
- * when this callback is run is the currently focused on
- * object. The event field of the callback may be animation
- * event if this callback is run in response to a timeout rather
- * than a user input.
- * @param event evt the event causing this hook to be run
- */
- protected void single_click_final_hook(event evt) {
- Vector v;
- /* is there a callback object?*/
- if (callback_obj()!=null) {
- /* grab the selected set */
- v=contents();
- callback_obj().callback(this,evt,SINGLE_CLICK_FINAL,
- v.elementAt(_focused));
- }
- }
- /**
- * This function is called when the user clicks the mouse
- * button on an item. It is called at the time the user
- * clicks, so there may be a double click coming down the pipe. <P>
- *
- * The parameter passed to callback function is the currently
- * focused on item.
- */
- protected void single_click_pending_hook(event evt) {
- Vector v;
- /* is there a callback object?*/
- if (callback_obj()!=null) {
- /* grab the selected set */
- v=contents();
- callback_obj().callback(this,evt,SINGLE_CLICK_PENDING,
- v.elementAt(_focused));
- }
- }
- /**
- * This function is called to determine if a drag is now beginning.
- * It makes that determination based on how far the mouse has moved
- * from the drag origin.
- *
- * It is called by the drag_feedback functions.
- * @param int local_x current x coordinate
- * @param int local_y current y coordinate
- */
- public boolean drag_ready(int local_x, int local_y) {
- int large_x, small_x, large_y, small_y;
-
- /* setup the big and small x values */
- if (local_x>drag_x_origin) {
- large_x=local_x;
- small_x=drag_x_origin;
- } else {
- large_x=drag_x_origin;
- small_x=local_x;
- }
- /* setup the big and small y values */
- if (local_y>drag_y_origin) {
- large_y=local_y;
- small_y=drag_y_origin;
- } else {
- large_y=drag_y_origin;
- small_y=local_y;
- }
- /* is it far enough? */
- if ((large_x-small_x >= DRAG_DISTANCE) ||
- (large_y-small_y>= DRAG_DISTANCE)) {
- /* tell the caller we're ready for a drag */
- return true;
- }
- /* not far enough */
- return false;
- }
- }
-
-
-
- /*=========================== COPYRIGHT NOTICE ===========================
-
- This file is part of the subArctic user interface toolkit.
-
- Copyright (c) 1996 Scott Hudson and Ian Smith
- All rights reserved.
-
- The subArctic system is freely available for most uses under the terms
- and conditions described in
- http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html
- and appearing in full in the lib/interactor.java source file.
-
- The current release and additional information about this software can be
- found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
-
- ========================================================================*/
-